﻿using S7.Net;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using App.Untiys;

namespace App.Untiys
{
    public class PLCManager
    {
        bool _bJudge = false;
        private Thread _thrSync;
        private bool _bRun = false;
        private Plc _objS7;

        public string E_Ip { set; get; }
        public short E_Rack { set; get; }
        public short E_Slot { set; get; }
        public int E_ReadCycle { set; get; }
        public int E_BeginAddress { set; get; }
        public int E_ReadLength { set; get; }
        public string E_DeviceName { set; get; }
        private static string _strClassName = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName;
        public event EventHandler<ActiveReadEventArgs> ActiveReadEvent = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="ip"></param>
        /// <param name="cycle"></param>
        /// <param name="readBeginAddress"></param>
        /// <param name="readLength"></param>
        public PLCManager(string name, string ip, int cycle, int readBeginAddress, int readLength)
        {
            E_Ip = ip;
            E_BeginAddress = readBeginAddress;
            E_ReadLength = readLength;
            E_ReadCycle = cycle < 500 ? 500 : cycle;
            E_DeviceName = name;
            E_Rack = 0;
            E_Slot = 1;
        }

        private void Moni()
        {
            while (true)
            {
                EventHelper.DispatchEventAsync<ActiveReadEventArgs>(this, this.ActiveReadEvent, new ActiveReadEventArgs("", E_DeviceName,new short[100] {
                1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                 1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                  1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                   1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                    1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                     1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                      1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                       1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                        1,2,3, 1, 2, 3 , 1, 2, 3 ,1,
                         1,2,3, 1, 2, 3 , 1, 2, 3 ,1

                }));
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool DoStart()
        {

            #region 模拟

            //_bRun = true;
            //_thrSync = new Thread(new ThreadStart(Moni));
            //_thrSync.IsBackground = true;
            //_thrSync.Start();
            //_bJudge = true;
            //return true;
            #endregion

            _bJudge = false;
            try
            {
                if (NetJudger.DoJudge(E_Ip))
                {
                    _objS7 = new Plc(CpuType.S7200Smart, E_Ip, E_Rack, E_Slot);
                    _objS7.Open();
                    if (_objS7.IsConnected)
                    {
                        _bRun = true;
                        _thrSync = new Thread(new ThreadStart(DoSync));
                        _thrSync.IsBackground = true;
                        _thrSync.Start();
                        _bJudge = true;
                    }
                    else
                        LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, $"模块:{E_DeviceName}  PLC地址:{E_Ip} 通讯连接失败...");
                }
                else
                    LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, $"模块:{E_DeviceName}  PLC地址:{E_Ip} 通讯连接失败,网络中断...");
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError($"{E_DeviceName}设备PLC连接失败,详见日志");
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, $"{E_DeviceName}设备PLC连接失败,详见日志");
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
            }
            return _bJudge;
        }

        /// <summary>
        /// 
        /// </summary>
        private void DoSync()
        {
            object _objValue;
            Random ro = new Random();
            System.Threading.Thread.Sleep(ro.Next(300, 1000));
            while (true)
            {
                if (_bRun)
                {
                    try
                    {
                    Reread:
                        //断线重连
                        if (_objS7 == null || !_objS7.IsConnected)
                        {

                            LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("模块:{0}  PLC地址:{1} 进入断线重连...", E_DeviceName, E_Ip));
                            Thread.Sleep(1000);
                            _objS7 = new Plc(CpuType.S71200, E_Ip, E_Rack, E_Slot);
                            _objS7.Open();
                            goto Reread;
                        }
                        else
                        {
                            Thread.Sleep(10);
                            //读取其他数据全部
                            System.Threading.Thread.Sleep(50);
                            _objValue = _objS7.Read(DataType.DataBlock, 1, E_BeginAddress, VarType.Word, E_ReadLength);
                            EventHelper.DispatchEventAsync<ActiveReadEventArgs>(this, this.ActiveReadEvent, new ActiveReadEventArgs("", E_DeviceName, _objValue));
                            System.Threading.Thread.Sleep(50);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("模块:{0}  PLC地址:{1} 数据读取失败...", E_DeviceName, E_Ip));
                        LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
                    }
                }
                Thread.Sleep(E_ReadCycle);
            }
        }

        /// <summary>
        /// 往地址写入值
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        public bool DoWrite(int address, short value)
        {
            int _iReSend = 1;
            bool _bResult = false;
        ReSend:
            try
            {
                int _iStep = 1;
            ReConnect:
                //断线重连
                if (_objS7 == null || !_objS7.IsConnected)
                {
                    Thread.Sleep(500);
                    _objS7 = new Plc(CpuType.S7200Smart, E_Ip, E_Rack, E_Slot);
                    _objS7.Open();
                    _iStep++;
                    if (_iStep <= 5)
                        goto ReConnect;
                }
                else
                {
                    //if (address == 0)
                    //    _objS7.Write(GetFullAddress4Byte(address), value);
                    //else
                    _objS7.Write(GetFullAddress(address), value);
                }
                    
                    //_objS7.Write(GetFullAddress("0.0"), value);
                _bResult = true;
            }
            catch (Exception ex)
            {
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("第{2}次往 模块:{0}  PLC地址:{1} 写入值失败...", E_DeviceName, E_Ip, _iReSend));
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
                _iReSend++;
                if (_iReSend <= 5)
                {
                    Thread.Sleep(1000);
                    goto ReSend;
                }
            }
            return _bResult;
        }

        /// <summary>
        /// 往地址写入值
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        public bool DoWrite(int address, short[] value)
        {
            try
            {
                int _iStep = 1;
            ReSend:
                //断线重连
                if (_objS7 == null || !_objS7.IsConnected)
                {
                    Thread.Sleep(500);
                    _objS7 = new Plc(CpuType.S7200Smart, E_Ip, E_Rack, E_Slot);
                    _objS7.Open();
                    _iStep++;
                    if (_iStep <= 10)
                        goto ReSend;
                }
                else
                    _objS7.Write(GetFullAddress(address), value);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("模块:{0}  PLC地址:{1} 写入值失败...", E_DeviceName, E_Ip));
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 往地址写入值
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        public object DoRead(int address)
        {
            try
            {
                int _iStep = 1;
            ReSend:
                //断线重连
                if (_objS7 == null || !_objS7.IsConnected)
                {
                    Thread.Sleep(500);
                    _objS7 = new Plc(CpuType.S7200Smart, E_Ip, E_Rack, E_Slot);
                    _objS7.Open();
                    _iStep++;
                    if (_iStep <= 10)
                        goto ReSend;
                }
                else
                   return _objS7.Read(DataType.DataBlock, 1, 276, VarType.Word, 1);
            }
            catch (Exception ex)
            {
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("模块:{0}  PLC地址:{1} 写入值失败...", E_DeviceName, E_Ip));
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
                return 0;
            }
            return 0;
        }

        /// <summary>
        /// 往地址写入值
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        public bool DoWrite(int address, object value)
        {
            try
            {
                int _iStep = 1;
            ReSend:
                //断线重连
                if (_objS7 == null || !_objS7.IsConnected)
                {
                    Thread.Sleep(500);
                    _objS7 = new Plc(CpuType.S7200Smart, E_Ip, E_Rack, E_Slot);
                    _objS7.Open();
                    _iStep++;
                    if (_iStep <= 10)
                        goto ReSend;
                }
                else
                    _objS7.Write(GetFullAddress(address), value);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, string.Format("模块:{0}  PLC地址:{1} 写入值失败...", E_DeviceName, E_Ip));
                LogHelper.DoWriteLogTypeClass(LogType.Program, _strClassName, ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 获取完整的地址
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        private string GetFullAddress(object address)
        {
            return string.Format("DB1.DBW{0}", address);
        }
        /// <summary>
        /// 获取完整的地址
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        private string GetFullAddress4Byte(object address)
        {
            return string.Format("DB1.DBW{0}", address);
        }
    }
}
